%name-prefix="rep"

%{
extern "C"
{
        int repparse(void);
        int replex(void);
        

}

#include <stdio.h>
#include <string.h>

void reperror(const char *str)
{
	fprintf(stderr,"error: %s\n",str);
}

int repwrap()
{
	return 1;
}

extern char* rep_input_ptr;

#include "types/Stack.h"

FloatStack fstack;

int param = 0;
float floatval[10];

int var = 0;
float floatvar[10];

int eval = 1;
int comp = 0;
float compare[2];

#include "turtle/Turtle.h"
#include "Types.h"

Turtle* thisTurtle;
RoutePlanner* thisPlanner;

string tempMeal;

string Turtle::feed(string meal) {
    if(!thisTurtle) {
        thisTurtle = this;
    }

    thisPlanner = thisTurtle->getPlanner();

    tempMeal = string();

    printf("Eating %s\n", meal.data());
    rep_input_ptr = strdup(meal.data());
    repparse();

    return tempMeal;
}

%}

%token REPLACE EXPAND PO PC C VAR;

%union 
{
	float number;
        char character;
        float (*flop2)(float, float);
}

%token <number> NUMBER;
%token <character> WALK SWIM
    TURN_LEFT TURN_RIGHT TURN_AROUND TURN_UPRIGHT
    NOSE_DOWN NOSE_UP
    ROLL_LEFT ROLL_RIGHT CHAR
    BO BC;
%token <flop2> FLOP2;

%%

commands: | commands command;

command: go | turn | branch | other;

other: CHAR parameters {
    if(param) {
        printf("\tAnything ");
        for(int i = 0; i < param; i++) {
                printf("%f ", floatval[i]);
        }
        printf("\n");
    } else {
        printf("\tAnything default (no action)\n");
            }

    tempMeal += thisPlanner->plan($1, floatval, param);
    param = 0;
};

go:
	WALK parameters {
		if(param) {
			printf("\tWalking ");
			for(int i = 0; i < param; i++) {
				printf("%f ", floatval[i]);			
			}
			printf("\n");

                        thisTurtle->walk(floatval[0]);
		} else {
			printf("\tWalking default\n");
                        thisTurtle->walk(1.0);
		}

                tempMeal += thisPlanner->plan($1, floatval, param);
                param = 0;
	} | SWIM parameters {
		if(param) {
			printf("\tSwimming ");
			for(int i = 0; i < param; i++) {
				printf("%f ", floatval[i]);
			}
			printf("\n");

                        thisTurtle->swim(floatval[0]);
		} else {
			printf("\tSwimming default\n");
                        thisTurtle->swim(1.0);
		}

                tempMeal += thisPlanner->plan($1, floatval, param);
                param = 0;
	};

turn:
	TURN_LEFT parameters {
		if(param) {
			printf("\tTurning left ");
			for(int i = 0; i < param; i++) {
				printf("%f ", floatval[i]);
			}
			printf("\n");

                        thisTurtle->rotate(PI/180.0 * floatval[0]);
		} else {
			printf("\tTurning left default\n");
                        thisTurtle->rotate(PI/180.0 * 45.0);
		}

                tempMeal += thisPlanner->duplicate($1, floatval, param);
                param = 0;
	} | TURN_RIGHT parameters {
		if(param) {
			printf("\tTurning right ");
			for(int i = 0; i < param; i++) {
				printf("%f ", floatval[i]);
			}
			printf("\n");

                        thisTurtle->rotate(-PI/180.0 * floatval[0]);
		} else {
			printf("\tTurning right default\n");
                        thisTurtle->rotate(-PI/180.0 * 45.0);
		}

                tempMeal += thisPlanner->duplicate($1, floatval, param);
                param = 0;
	} | NOSE_UP parameters {
		if(param) {
			printf("\tNose up ");
			for(int i = 0; i < param; i++) {
				printf("%f ", floatval[i]);
			}
			printf("\n");

                        thisTurtle->pitch(PI/180.0 * floatval[0]);
		} else {
			printf("\tNose up default\n");
                        thisTurtle->pitch(PI/180.0 * 45.0);
		}

                tempMeal += thisPlanner->duplicate($1, floatval, param);
                param = 0;
	} | NOSE_DOWN parameters {
		if(param) {
			printf("\tNose down ");
			for(int i = 0; i < param; i++) {
				printf("%f ", floatval[i]);
			}
			printf("\n");

                        thisTurtle->pitch(-PI/180.0 * floatval[0]);
		} else {
			printf("\tNose down default\n");
                        thisTurtle->pitch(PI/180.0 * 45.0);
		}

                tempMeal += thisPlanner->duplicate($1, floatval, param);
                param = 0;
	} | ROLL_LEFT parameters {
		if(param) {
			printf("\tRole left ");
			for(int i = 0; i < param; i++) {
				printf("%f ", floatval[i]);
			}
			printf("\n");

                        thisTurtle->roll(PI/180.0 * floatval[0]);
		} else {
			printf("\tRoll left default\n");
                        thisTurtle->roll(PI/180.0 * 45.0);
		}

                tempMeal += thisPlanner->duplicate($1, floatval, param);
                param = 0;
	} | ROLL_RIGHT parameters {
		if(param) {
			printf("\tRole right ");
			for(int i = 0; i < param; i++) {
				printf("%f ", floatval[i]);
			}
			printf("\n");

                        thisTurtle->roll(-PI/180.0 * floatval[0]);
		} else {
			printf("\tRoll right default\n");
                        thisTurtle->roll(-PI/180.0 * 45.0);
		}

                tempMeal += thisPlanner->duplicate($1, floatval, param);
                param = 0;
	} | TURN_AROUND {
                printf("\tTurn around\n");
                thisTurtle->turn();

                tempMeal += thisPlanner->duplicate($1, 0);
	} | TURN_UPRIGHT {
                printf("\tTurn upright\n");
                thisTurtle->upright();

                tempMeal += thisPlanner->duplicate($1, 0);
        };

branch: BO {
        printf("\tBranching\n");

        thisTurtle->sleep();
        tempMeal += thisPlanner->duplicate($1, 0);
    } | BC {
        printf("\tBranch end\n");

        thisTurtle->wakeup();
        tempMeal += thisPlanner->duplicate($1, 0);
    };

parameters: | PO paramlist PC;

paramlist: | param {
    float res = 0;
    if(fstack.size() > 0) {
        res = fstack[0];
        if(fstack.size() > 1) {
            reperror("Arithmetic expression seems to be not well-formed!\n");
        }
    }

    floatval[param] = res;
    param++;

    fstack.reset();
} | paramlist C param {
    float res = 0;
    if(fstack.size() > 0) {
        res = fstack[0];
        if(fstack.size() > 1) {
            reperror("Arithmetic expression seems to be not well-formed!\n");
        }
    }

    floatval[param] = res;
    param++;

    fstack.reset();
};

param: NUMBER {
    fstack.push($1);
} | NUMBER FLOP2 NUMBER {
    fstack.push($2($1, $3));
} | PO NUMBER FLOP2 NUMBER PC {
    fstack.push($3($2, $4));
} | param FLOP2 param {
    if(fstack.size() >= 2) {
        fstack.push($2(*fstack.pop(), *fstack.pop()));
    } else {
        printf("Upps, less than two floats on stack\n");
    }
};

